'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { unstable_composeClasses as composeClasses } from '@mui/base';
import { OverridableComponent } from '@mui/types';
import capitalize from '@mui/utils/capitalize';
import useControlled from '@mui/utils/useControlled';
import useId from '@mui/utils/useId';
import { useThemeProps } from '../styles';
import styled from '../styles/styled';
import { getAccordionUtilityClass } from './accordionClasses';
import { AccordionProps, AccordionOwnerState, AccordionTypeMap } from './AccordionProps';
import useSlot from '../utils/useSlot';
import AccordionContext from './AccordionContext';
import { StyledListItem } from '../ListItem/ListItem';
import accordionDetailsClasses from '../AccordionDetails/accordionDetailsClasses';

const useUtilityClasses = (ownerState: AccordionOwnerState) => {
  const { variant, color, expanded, disabled } = ownerState;
  const slots = {
    root: [
      'root',
      expanded && 'expanded',
      disabled && 'disabled',
      color && `color${capitalize(color)}`,
      variant && `variant${capitalize(variant)}`,
    ],
  };

  return composeClasses(slots, getAccordionUtilityClass, {});
};

const AccordionRoot = styled(StyledListItem as unknown as 'div', {
  name: 'JoyAccordion',
  slot: 'Root',
  overridesResolver: (props, styles) => styles.root,
})<{ ownerState: AccordionOwnerState }>({
  borderBottom: 'var(--Accordion-borderBottom)',
  '&[data-first-child]': {
    '--ListItem-radius': 'var(--unstable_List-childRadius) var(--unstable_List-childRadius) 0 0',
  },
  '&[data-last-child]': {
    '--ListItem-radius': '0 0 var(--unstable_List-childRadius) var(--unstable_List-childRadius)',
    '& [aria-expanded="true"]': {
      '--ListItem-radius': '0',
    },
    [`& .${accordionDetailsClasses.root}`]: {
      '--AccordionDetails-radius':
        '0 0 var(--unstable_List-childRadius) var(--unstable_List-childRadius)',
    },
  },
  '&:not([data-first-child]):not([data-last-child])': {
    '--ListItem-radius': '0',
  },
});
/**
 *
 * Demos:
 *
 * - [Accordion](https://mui.com/joy-ui/react-accordion/)
 *
 * API:
 *
 * - [Accordion API](https://mui.com/joy-ui/api/accordion/)
 */
const Accordion = React.forwardRef(function Accordion(inProps, ref) {
  const props = useThemeProps<typeof inProps & AccordionProps>({
    props: inProps,
    name: 'JoyAccordion',
  });

  const {
    accordionId: idOverride,
    component = 'div',
    color = 'neutral',
    children,
    defaultExpanded = false,
    disabled = false,
    expanded: expandedProp,
    onChange,
    variant = 'plain',
    slots = {},
    slotProps = {},
    ...other
  } = props;

  const accordionId = useId(idOverride);

  const [expanded, setExpandedState] = useControlled({
    controlled: expandedProp,
    default: defaultExpanded,
    name: 'Accordion',
    state: 'expanded',
  });

  const handleChange = React.useCallback(
    (event: React.SyntheticEvent) => {
      setExpandedState(!expanded);

      if (onChange) {
        onChange(event, !expanded);
      }
    },
    [expanded, onChange, setExpandedState],
  );

  const contextValue = React.useMemo(
    () => ({ accordionId, expanded, disabled, toggle: handleChange }),
    [accordionId, expanded, disabled, handleChange],
  );

  const externalForwardedProps = { ...other, component, slots, slotProps };

  const ownerState = {
    ...props,
    component,
    color,
    variant,
    expanded,
    disabled,
    nested: true, // for the ListItem styles
  };

  const classes = useUtilityClasses(ownerState);

  const [SlotRoot, rootProps] = useSlot('root', {
    ref,
    className: classes.root,
    elementType: AccordionRoot,
    externalForwardedProps,
    ownerState,
  });

  return (
    <AccordionContext.Provider value={contextValue}>
      <SlotRoot {...rootProps}>
        {React.Children.map(children, (child, index) =>
          React.isValidElement(child) && index === 0
            ? React.cloneElement(child, {
                // @ts-ignore: to let ListItem knows when to apply margin(Inline|Block)Start
                'data-first-child': '',
              })
            : child,
        )}
      </SlotRoot>
    </AccordionContext.Provider>
  );
}) as OverridableComponent<AccordionTypeMap>;

Accordion.propTypes /* remove-proptypes */ = {
  // ┌────────────────────────────── Warning ──────────────────────────────┐
  // │ These PropTypes are generated from the TypeScript type definitions. │
  // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
  // └─────────────────────────────────────────────────────────────────────┘
  /**
   * The id to be used in the AccordionDetails which is controlled by the AccordionSummary.
   * If not provided, the id is autogenerated.
   */
  accordionId: PropTypes.string,
  /**
   * Used to render icon or text elements inside the Accordion if `src` is not set.
   * This can be an element, or just a string.
   */
  children: PropTypes.node,
  /**
   * The color of the component. It supports those theme colors that make sense for this component.
   * @default 'neutral'
   */
  color: PropTypes.oneOf(['danger', 'neutral', 'primary', 'success', 'warning']),
  /**
   * The component used for the root node.
   * Either a string to use a HTML element or a component.
   */
  component: PropTypes.elementType,
  /**
   * If `true`, expands the accordion by default.
   * @default false
   */
  defaultExpanded: PropTypes.bool,
  /**
   * If `true`, the component is disabled.
   * @default false
   */
  disabled: PropTypes.bool,
  /**
   * If `true`, expands the accordion, otherwise collapse it.
   * Setting this prop enables control over the accordion.
   */
  expanded: PropTypes.bool,
  /**
   * Callback fired when the expand/collapse state is changed.
   *
   * @param {React.SyntheticEvent} event The event source of the callback. **Warning**: This is a generic event not a change event.
   * @param {boolean} expanded The `expanded` state of the accordion.
   */
  onChange: PropTypes.func,
  /**
   * The props used for each slot inside.
   * @default {}
   */
  slotProps: PropTypes.shape({
    root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
  }),
  /**
   * The components used for each slot inside.
   * @default {}
   */
  slots: PropTypes.shape({
    root: PropTypes.elementType,
  }),
  /**
   * The system prop that allows defining system overrides as well as additional CSS styles.
   */
  sx: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])),
    PropTypes.func,
    PropTypes.object,
  ]),
  /**
   * The [global variant](https://mui.com/joy-ui/main-features/global-variants/) to use.
   * @default 'plain'
   */
  variant: PropTypes.oneOf(['outlined', 'plain', 'soft', 'solid']),
} as any;

export default Accordion;
